﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Windows.Media.Animation;
namespace RippleEffect
{
    public class Ripple
    {

        private List<Grid> RippleElement = new List<Grid>();
        private List<GeometryGroup> RipplePath = new List<GeometryGroup>();
        private List<DoubleAnimationUsingKeyFrames> AnimationList = new List<DoubleAnimationUsingKeyFrames>();
        private List<DoubleAnimationUsingKeyFrames> FadeOut = new List<DoubleAnimationUsingKeyFrames>();
        private List<DoubleAnimationUsingKeyFrames> Distortion = new List<DoubleAnimationUsingKeyFrames>();
        private List<Duration> duration = new List<Duration>();
        private Storyboard board = new Storyboard();
        public Grid MainCanvas = null;
        public Brush Background;

        private List<LinearDoubleKeyFrame> distort1 = new List<LinearDoubleKeyFrame>();
        private List<LinearDoubleKeyFrame> distort2 = new List<LinearDoubleKeyFrame>();
        private List<LinearDoubleKeyFrame> distort3 = new List<LinearDoubleKeyFrame>();
        private List<LinearDoubleKeyFrame> distort4 = new List<LinearDoubleKeyFrame>();
        private List<LinearDoubleKeyFrame> fadestart = new List<LinearDoubleKeyFrame>();
        private List<LinearDoubleKeyFrame> fadeend = new List<LinearDoubleKeyFrame>();
        private List<LinearDoubleKeyFrame> start = new List<LinearDoubleKeyFrame>();
        private List<LinearDoubleKeyFrame> end = new List<LinearDoubleKeyFrame>();

        private double pTotalDuration = 0;
        private double pRippleCount = 0;
        private ImageSource RippleImage = null;

        private GeometryGroup CreateRipple(double Radius, double InnerRadius, Point Center)
        {            
            GeometryGroup RippleGeometry = new GeometryGroup();
            EllipseGeometry OuterCircle = new EllipseGeometry();
            OuterCircle.Center = Center;
            OuterCircle.RadiusX = Radius;
            OuterCircle.RadiusY = Radius;
            EllipseGeometry InnerCircle = new EllipseGeometry();
            InnerCircle.Center = Center;
            InnerCircle.RadiusX = Radius - InnerRadius;
            InnerCircle.RadiusY = Radius - InnerRadius;
            RippleGeometry.Children.Add(OuterCircle);
            RippleGeometry.Children.Add(InnerCircle);
            RippleGeometry.FillRule = FillRule.EvenOdd;
            return RippleGeometry;
           
        }

        private void CreateCircle(double Radius, double InnerRadius, Point Center)
        {
            
            for (int i = 0; i < 3; i++)
            {
                GeometryGroup g = CreateRipple(Radius, InnerRadius, Center);
                g.Transform = new ScaleTransform();
                ((ScaleTransform)g.Transform).CenterX = Center.X;
                ((ScaleTransform)g.Transform).CenterY = Center.Y;
                ((ScaleTransform)g.Transform).ScaleX = 0.1;
                ((ScaleTransform)g.Transform).ScaleY = 0.1;
                RipplePath.Add(g);
                this.RippleElement[i].Clip=RipplePath[i];
            }           
            

             


        }
       
        private Grid CreateCanvas(Brush BackGround)
        {
            Grid RippleElement = new Grid();
            
            RippleElement.HorizontalAlignment = HorizontalAlignment.Stretch;
            RippleElement.VerticalAlignment = VerticalAlignment.Stretch;
            //RippleElement.Opacity = 0.2;
            ImageBrush img = new ImageBrush();
            img.ImageSource = RippleImage;
            RippleElement.Background = img;
            return RippleElement;
        }

        public void RunRippleAnimation()
        {
            this.board.Begin();
        }

        public Ripple(double Radius, double RippleThickness, Point Center,Grid Holder,double TotalTime,double RippleCount,ImageSource RippleImage)
        {
            this.RippleImage = RippleImage;
            this.pTotalDuration = TotalTime;
            this.pRippleCount = RippleCount;

            board.Completed += new EventHandler(board_Completed);
            MainCanvas = Holder;
          //  board.RepeatBehavior = RepeatBehavior.Forever;



            for (int i = 0; i < this.pRippleCount*2; i++)
            {
                this.AnimationList.Add(new DoubleAnimationUsingKeyFrames());
                start.Add(new LinearDoubleKeyFrame());
                end.Add(new LinearDoubleKeyFrame());
            }


            for (int i = 0; i < this.pRippleCount*2; i++)
            {
                this.Distortion.Add(new DoubleAnimationUsingKeyFrames());
                this.distort1.Add(new LinearDoubleKeyFrame());
                this.distort2.Add(new LinearDoubleKeyFrame());
                this.distort3.Add(new LinearDoubleKeyFrame());
                this.distort4.Add(new LinearDoubleKeyFrame());
            }

            for (int i = 0; i < this.pRippleCount; i++)
            {
                this.FadeOut.Add(new DoubleAnimationUsingKeyFrames());
                this.fadestart.Add(new LinearDoubleKeyFrame());
                this.fadeend.Add(new LinearDoubleKeyFrame());
            }


            double overalltime = pTotalDuration / RippleCount;

            double timefactor = overalltime; 
            double incrimnetfactor = overalltime; 
            double endtimeframe = timefactor;
            double endfadetime = timefactor;
            double enddistort = timefactor / 2;
            double MaxfadeTime = endfadetime + (incrimnetfactor * RippleCount);
            
            for (int i = 0; i < RippleCount; i++)
            {

                double starthere = endfadetime / 2;
                double endhere = endfadetime;

                fadestart[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(starthere));
                fadestart[i].Value = 1;
                fadeend[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(endhere));
                fadeend[i].Value = 0;
                //decreasefactor -= incrimnetfactor;
                endfadetime += incrimnetfactor;
            }

            for (int i = 0; i < RippleCount*2; i++)
            {
                distort1[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0));
                distort1[i].Value = 1.015;
                distort2[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(enddistort /2));
                distort2[i].Value = 1;
                distort3[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(enddistort / 2));
                distort3[i].Value = 1;
                distort4[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(enddistort));
                distort4[i].Value = 1.015;
                if (i % 2 != 0)
                {
                    enddistort += incrimnetfactor;
                }
            }

            for (int i = 0; i < RippleCount*2; i++)
            {
                this.Distortion[i].KeyFrames.Add(distort1[i]);
                this.Distortion[i].KeyFrames.Add(distort2[i]);
                this.Distortion[i].KeyFrames.Add(distort3[i]);
                this.Distortion[i].KeyFrames.Add(distort4[i]);
            }

            for (int i = 0; i < RippleCount; i++)
            {
                this.FadeOut[i].KeyFrames.Add(fadestart[i]);
                this.FadeOut[i].KeyFrames.Add(fadeend[i]);
            }


            for (int i = 0; i < RippleCount*2; i++)
            {
                start[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0));
                start[i].Value = 0.01;
                end[i].KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(endtimeframe));
                end[i].Value = 1;
                if (i % 2!=0)
                {
                    endtimeframe += incrimnetfactor;
                }
            }

            for (int i = 0; i < RippleCount*2; i++)
            {
                this.AnimationList[i].KeyFrames.Add(start[i]);                
                this.AnimationList[i].KeyFrames.Add(end[i]);
            }


            for (int i = 0; i < RippleCount; i++)
            {
               Grid a = CreateCanvas(this.Background);
               a.RenderTransform = new ScaleTransform();
               ((ScaleTransform)a.RenderTransform).CenterX = Center.X;
               ((ScaleTransform)a.RenderTransform).CenterY = Center.Y;
               ((ScaleTransform)a.RenderTransform).ScaleX = 1;
               ((ScaleTransform)a.RenderTransform).ScaleY = 1;
               RippleElement.Add(a);
               MainCanvas.Children.Add(a);
            }
                
            
            

            CreateCircle(Radius, RippleThickness, Center);


            for (int i = 0; i < RippleCount*2; i += 2)
            {
                Storyboard.SetTargetProperty(this.AnimationList[i], new PropertyPath("(GeometryGroup.Transform).(ScaleTransform.ScaleX)"));
                Storyboard.SetTargetProperty(this.AnimationList[i+1], new PropertyPath("(GeometryGroup.Transform).(ScaleTransform.ScaleY)"));              
            }

            for (int i = 0; i < RippleCount*2; i += 2)
            {
                Storyboard.SetTargetProperty(this.Distortion[i], new PropertyPath("(Grid.RenderTransform).(ScaleTransform.ScaleX)"));
                Storyboard.SetTargetProperty(this.Distortion[i + 1], new PropertyPath("(Grid.RenderTransform).(ScaleTransform.ScaleY)"));
            }


            for (int i = 0; i < RippleCount; i++)
            {
                Storyboard.SetTargetProperty(this.FadeOut[i], new PropertyPath("(Grid.Opacity)"));
            }


            for (int i = 0; i < RippleCount; i++)
            {
                Storyboard.SetTarget(this.FadeOut[i], this.RippleElement[i]);
            }

            for (int i = 0,l=0; i < RippleCount*2; i += 2,l++)
            {
                Storyboard.SetTarget(this.AnimationList[i], this.RipplePath[l]);
                Storyboard.SetTarget(this.AnimationList[i+1], this.RipplePath[l]);
            }

            for (int i = 0, l = 0; i < RippleCount*2; i += 2, l++)
            {
                Storyboard.SetTarget(this.Distortion[i], this.RippleElement[l]);
                Storyboard.SetTarget(this.Distortion[i + 1], this.RippleElement[l]);
            }


            for (int i = this.Distortion.Count - 1; i >= 0; i--)
            {
                board.Children.Add(this.Distortion[i]);
            }

            for (int i = AnimationList.Count - 1; i >= 0; i--)
            {
                board.Children.Add(this.AnimationList[i]);
            }

            for (int i = FadeOut.Count - 1; i >= 0; i--)
            {
                board.Children.Add(this.FadeOut[i]);
            }
            
           
        }

        void board_Completed(object sender, EventArgs e)
        {
            for (int i = 0; i < this.RippleElement.Count; i++)
            {
                ((Grid)RippleElement[i].Parent).Children.Remove(this.RippleElement[i]);
            }
        }
    }
}
